/************************************************************************/
/* Game                                                                 */
/************************************************************************/
#include "Game/TowerDefense.h"

namespace TD_Game {

	const unsigned int TowerDefense::m_initialLives = 20;
	const unsigned int TowerDefense::m_initialMoney = 10;
	const unsigned int TowerDefense::m_statusFontSize = 34 * screenWidth/1024.0;
   

	/************************************************************************/
	/* Ingame                                                               */
	/************************************************************************/

	void TowerDefense::createLevel() {
      float multiplier=1; 
      switch(m_difficultySelected)
      {
      case 0:
         multiplier = 0.88;
         break;
      case 1:
         multiplier = 1;
         break;
      case 2:
         multiplier = 1.12;
         break;
      }
		/************************************************************************/
		/* Hard level                                                           */
		/************************************************************************/
		m_waves.push_back(WaveInfo(NES_Small_Mario_SPM1,	normal,	5/60.0, 30*multiplier, 10, 1, 600));
		m_waves.push_back(WaveInfo(NES_Big_Mario_SPM1,	normal,	5/60.0, 70*multiplier, 10, 1, 600));
		
		m_waves.push_back(WaveInfo(NES_Big_Mario_SPM1,	normal,	5/60.0, 70*multiplier, 10, 1, 600));
		m_waves.push_back(WaveInfo(NES_Fire_Mario_SPM1,	normal, 5/60.0, 100*multiplier, 10, 1, 600));
		m_waves.push_back(WaveInfo(NES_Small_Mario_SPM2,	normal, 10/60.0, 110*multiplier, 10, 1, 400));//fast
		m_waves.push_back(WaveInfo(NES_Big_Mario_SPM2,	group, 5/60.0, 150*multiplier, 10, 1, 200));

		m_waves.push_back(WaveInfo(NES_Big_Mario_SPM2,	group, 5/60.0, 200*multiplier, 10, 1, 200));
		m_waves.push_back(WaveInfo(NES_Nabo_Mario_SPM2,	normal, 5/60.0, 250*multiplier, 10, 1, 500));
		m_waves.push_back(WaveInfo(NES_Nabo_Mario_SPM2,	immune, 5/60.0, 300*multiplier, 10, 1, 500));//immune
		m_waves.push_back(WaveInfo(NES_Small_Mario_SPM3,	normal, 5/60.0, 350*multiplier, 10, 1, 300));
		m_waves.push_back(WaveInfo(NES_Big_Mario_SPM3,	normal,	5/60.0, 2800*multiplier, 1, 20, 500));  //WAVE 10 BOSS

		m_waves.push_back(WaveInfo(NES_Rolling_Mario_SPM3,normal,	5/60.0, 400*multiplier, 10, 2, 500));
		m_waves.push_back(WaveInfo(NES_Tail_Mario_SPM3,	normal,	5/60.0, 420*multiplier, 10, 2, 500));//fast
		m_waves.push_back(WaveInfo(NES_Fire_Mario_SPM3,	group, 5/60.0, 460*multiplier, 10, 2, 200));//group
		m_waves.push_back(WaveInfo(NES_Fox_Mario_SPM3,	normal, 5/60.0, 500*multiplier, 10, 2, 500));
		m_waves.push_back(WaveInfo(SNES_Big_Mario_Running,normal, 11/60.0, 510*multiplier, 10, 2, 400));//fast

		m_waves.push_back(WaveInfo(SNES_Hammer_Mario,		immune, 5/60.0, 550*multiplier, 10, 2, 500)); //immune
		m_waves.push_back(WaveInfo(SNES_Big_Mario_Running,normal, 11/60.0, 540*multiplier, 10, 2, 400));//fast
		m_waves.push_back(WaveInfo(SNES_Flower_Mario,		group, 5/60.0, 570*multiplier, 10, 3, 200));//group
		m_waves.push_back(WaveInfo(SNES_Flying_Mario1,	normal, 5/60.0, 640*multiplier, 10, 3, 500));
		m_waves.push_back(WaveInfo(SNES_Flying_Mario2,	normal, 10/60.0, 6000*multiplier, 1, 3, 500));//WAVE 20 boss

		m_waves.push_back(WaveInfo(SNES_Flying_Mario3,	normal, 5/60.0, 680*multiplier, 10, 3, 500));
		m_waves.push_back(WaveInfo(SNES_Big_Mario_Doc,	normal, 5/60.0, 740*multiplier, 10, 3, 500));
		m_waves.push_back(WaveInfo(SNES_Big_Mario_Running_Doc, group, 5/60.0, 790*multiplier, 10, 3, 500));//group
		m_waves.push_back(WaveInfo(SNES_Flying_Mario_Doc, immune, 5/60.0, 840*multiplier, 10, 3, 500));
		m_waves.push_back(WaveInfo(SNES_Flying_Mario_Doc2, normal, 5/60.0, 910*multiplier, 10, 3, 500));

		m_waves.push_back(WaveInfo(SNES_Flying_Mario_Doc3, normal, 5/60.0, 1020*multiplier, 10, 4, 500));
		m_waves.push_back(WaveInfo(NES_Small_Mario_SPM1,	normal,	11/60.0, 1090*multiplier, 10, 4, 500));//fast
		m_waves.push_back(WaveInfo(NES_Big_Mario_SPM1,	group,	5/60.0, 1160*multiplier, 10, 4, 150));//group
		m_waves.push_back(WaveInfo(NES_Small_Mario_SPM1,	normal,	5/60.0, 1220*multiplier, 10, 4, 500));
		m_waves.push_back(WaveInfo(NES_Big_Mario_SPM1,	immune,	5/60.0, 12000*multiplier, 2, 40, 300));//WAVE 30 BOSS IMMUNE

		m_waves.push_back(WaveInfo(NES_Small_Luigi,	normal,	10/60.0, 1280*multiplier, 10, 5, 300));//fast
		m_waves.push_back(WaveInfo(NES_Luigi,	group,	5/60.0, 1350*multiplier, 10, 5, 150));
		m_waves.push_back(WaveInfo(NES2_Luigi,	normal,	10/60.0, 1400*multiplier, 10, 5, 300));
		m_waves.push_back(WaveInfo(NES2_Toad,	immune,	10/60.0, 1480*multiplier, 10, 5, 300));//immune
		m_waves.push_back(WaveInfo(NES2_Peach,	normal,	10/60.0, 1550*multiplier, 10, 5, 400));


		m_waves.push_back(WaveInfo(NES3_Small_Luigi,	normal,	10/60.0, 1590*multiplier, 10, 5, 399));//fast
		m_waves.push_back(WaveInfo(NES3_Luigi,	normal,	5/60.0, 1670*multiplier, 10, 5, 400));
		m_waves.push_back(WaveInfo(NES3_Luigi_Running,	group,	5/60.0, 1730*multiplier, 10, 5, 150));//group
		m_waves.push_back(WaveInfo(NES3_Tail_Luigi,	immune,	5/60.0, 1800*multiplier, 10, 5, 200));//immune
		m_waves.push_back(WaveInfo(NES3_Tail_Luigi_Running,	immune,	8/60.0, 24000*multiplier, 2, 5, 300));//WAVE 40 BOSS

		m_waves.push_back(WaveInfo(SNES_Luigi,	normal,	5/60.0, 1870*multiplier, 10, 5, 300));
		m_waves.push_back(WaveInfo(SNES_Luigi_Running,	normal,	11/60.0, 1890*multiplier, 10, 5, 400));//fast
		m_waves.push_back(WaveInfo(SNES_Peach,	immune,	5/60.0, 1990*multiplier, 10, 5, 300));//immune
		m_waves.push_back(WaveInfo(SNES_Peach_Running,	immune,	9/60.0, 1990*multiplier, 10, 5, 300));//immune fast
		m_waves.push_back(WaveInfo(SNES_Princess,	group,	5/60.0, 2100, 10, 5, 150));//group

		m_waves.push_back(WaveInfo(SNES_Princess_Running,	group,	9/60.0, 2100*multiplier, 10, 6, 150));//group fast
		m_waves.push_back(WaveInfo(Protoman, group, 5/60.0, 2100*multiplier, 10, 10, 200));
		m_waves.push_back(WaveInfo(Cutman, normal, 5/60.0, 2500*multiplier, 10, 15, 300));
		m_waves.push_back(WaveInfo(BlackBomberman, group, 5/60.0, 2800*multiplier, 10, 15, 150));
		m_waves.push_back(WaveInfo(WhiteBomberman, normal, 5/60.0, 3600*multiplier, 10, 15, 300));

		m_waves.push_back(WaveInfo(Megaman, immune, 5/60.0, 28000*multiplier, 3, 40, 150));//immune
		m_waves.push_back(WaveInfo(Sonic, normal, 8/60.0, 30000*multiplier, 3, 40, 200));//fast
		m_waves.push_back(WaveInfo(Sonic_Rolling, immune, 11/60.0, 34000*multiplier, 3, 40, 200));//fast

	}


	void TowerDefense::initGameSystem() {
		m_fpsTimer.start();
		m_updateTimer.start();
		m_numFrames = 0;
		m_quit = false;
		m_gameStarted = m_levelCreated = false;
		m_currWave = 0;

	}

	void TowerDefense::initGraphicalElements() {

#ifdef WIN32
		m_pMainScreen = new Screen("TestPane", screenWidth, screenHeight, 16);
#elif _WII
		m_pMainScreen = new Screen("TestPane", screenWidth, screenHeight, 16);
#endif

		m_terrainTileset.loadTileset("grass1small.bmp", 0.0292968*screenWidth, 0.040364*screenHeight, Color::BLACK);
		
		#ifdef WIN32
		m_terrain.loadTilemap(&m_terrainTileset, "Misc/pathmap.txt", m_pMainScreen->getCanvasPosition(),
			Coord2D(32.0, 32.0), Coord2D(8, 6));
		#elif _WII
		m_terrain.loadTilemap(&m_terrainTileset, "Misc/pathmap.txt", m_pMainScreen->getCanvasPosition(),
			Coord2D(0.0292968*screenWidth, 0.040364*screenHeight), Coord2D(8, 6));
		#endif

		m_terrainTilesize = m_terrainTileset.getTilesize() * 3;

		m_pMainScreen->setBackgroundImage("background.png");

		m_pPipeFront = new Tile(Coord2D(0.005*screenWidth, 0.09375*screenHeight), Coord2D(0.07635*screenWidth, 0.0725*screenHeight), imgTile, NULL, TD_Resources::ResourceManager::loadImage("pipeFront.png", Color::PINK));
		m_pCloud = new Cloud(Coord2D(200, 200));
		
	}

	void TowerDefense::initGUI() {
		m_pCreepInfo = new MarioInfoPanel();
		m_pTowerInfo = new TowerInfoPanel();
		m_showTowerInfo = m_showCreepInfo  = false;
		m_pTowerMenu = new TowerMenuPanel();
		m_pWaveInfoPanel = new WaveInfoPanel();

		m_showingCreepID = -1; //Invalid

		m_pEntryScreen = new EntryScreen();
		//Saving memory
		m_pGameOverScreen = NULL;
		m_pMenuPanel = new MenuPanel();
		m_pMenuPanel->setVisible(false);
		m_pFadescreen = new Fadescreen();
		m_pFadescreen->startFadeIn(10/frameRate);

		//User variables
		m_pMoneyMsg = m_pLivesMsg = m_pScoreMsg = m_pLevelMsg = NULL;
		m_pWarningMsg = NULL;

		setScore(0);
		setLevel(m_currWave + 1);
		setMoney(m_initialMoney);
		m_oldLives = m_initialLives;
		setLives(m_initialLives);

	}

	void TowerDefense::initUserInteraction() {
		m_pInputManager = new InputManager(&m_terrain, m_pTowerInfo, m_pTowerMenu, m_pCreepInfo, m_pMenuPanel);
		m_isInsertingInvalidTower = m_isInsertingTower = false;

		m_pInsertTowerAS = AnimationSetFactory::createTowerAnimationSet(insertTower, "Idle");
		m_pInsertInvalidTowerAS = AnimationSetFactory::createTowerAnimationSet(insertInvalidTower, "Idle");

		SDLCursor::setCursor(arrowCursor);
	}


	/************************************************************************/
	/* ctors and dtors                                                      */
	/************************************************************************/

	TowerDefense::TowerDefense() {
		initGameSystem();
		initGraphicalElements();
		initGUI();
		initUserInteraction();
		preallocateResources();
		

		m_currGameArea = atEntryScreen;
		m_nextGameArea = invalidArea;

		
	}

	TowerDefense::~TowerDefense() {
		Utils::safeDelete<Tile>(m_pPipeFront);
		Utils::safeDelete<EntryScreen>(m_pEntryScreen);
		Utils::safeDelete<GameOverScreen>(m_pGameOverScreen);
		Utils::safeDelete<Screen>(m_pMainScreen);
		Utils::safeDelete<TowerMenuPanel>(m_pTowerMenu);
		Utils::safeDelete<TowerInfoPanel>(m_pTowerInfo);
		Utils::safeDelete<MarioInfoPanel>(m_pCreepInfo);
		Utils::safeDelete<WaveInfoPanel>(m_pWaveInfoPanel);
		Utils::safeDelete<MenuPanel>(m_pMenuPanel);
		Utils::safeDelete<Fadescreen>(m_pFadescreen);
		Utils::safeDelete<TextMessage>(m_pLivesMsg);
		Utils::safeDelete<TextMessage>(m_pMoneyMsg);
		Utils::safeDelete<TextMessage>(m_pLevelMsg);
		Utils::safeDelete<TextMessage>(m_pScoreMsg);
		Utils::safeDelete<FadingMessage>(m_pWarningMsg);
		Utils::safeDelete<Cloud>(m_pCloud);
		Utils::safeDelete<InputManager>(m_pInputManager);
		Utils::safeDelete<AnimationSet>(m_pInsertTowerAS);
		Utils::safeDelete<AnimationSet>(m_pInsertInvalidTowerAS);
	}

	void TowerDefense::preallocateResources() {
		m_musicIndex = 0;
		m_musicList.push_back("SFX/music/musica4.mp3");
		m_musicList.push_back("SFX/music/musica5.mp3");
		m_musicList.push_back("SFX/music/musica6.mp3");
		m_musicList.push_back("SFX/music/musica3.mp3");
		m_musicList.push_back("SFX/music/musica2.mp3");
		m_musicList.push_back("SFX/music/musica1.mp3");
		m_pBackgroundMusic = TD_Resources::ResourceManager::loadMusic(m_musicList[m_musicIndex]);
		m_pMarioPassed1 = TD_Resources::ResourceManager::loadSound("SFX/sounds/marioIhi2.wav");
		m_pMarioPassed2 = TD_Resources::ResourceManager::loadSound("SFX/sounds/marioUhu2.wav");
		m_pMarioPassed3 = TD_Resources::ResourceManager::loadSound("SFX/sounds/marioYeahHahaha2.wav");
		m_pCoinSound = TD_Resources::ResourceManager::loadSound("SFX/sounds/coin.wav");
		m_pPauseSound = TD_Resources::ResourceManager::loadSound("SFX/sounds/Pause.wav");
		m_pMarioHurry = TD_Resources::ResourceManager::loadSound("SFX/sounds/fastLevel.wav");
		m_pPipeWarp = TD_Resources::ResourceManager::loadSound("SFX/sounds/Pipe Warp.wav");
		
	}

	void TowerDefense::processGameEvents() {

		interaction_t interaction;
		interaction = m_pInputManager->process(m_pMainScreen, (1000/frameRate));
		unsigned int upgradeCost;
		switch (interaction.type) {
			case towerSelected:
				if(m_money < interaction.value) {
					setWarningMsg("Dinheiro insuficiente");
					m_isInsertingTower = false;
					m_isInsertingInvalidTower = false;
					m_pInputManager->resetSelection();
				} 
			break;
			case towerInserting:
				if(m_money >= interaction.value) {
					m_isInsertingTower = true;
					m_isInsertingInvalidTower = false;
					m_insertingTowerPosition = interaction.position;
				} else { //not enough money
					m_isInsertingInvalidTower = true;
					m_isInsertingTower = false;
					setWarningMsg("Dinheiro insuficiente");
				}
			break;

			case towerInsertingInvalid:
				m_isInsertingTower = false;
				m_isInsertingInvalidTower = true;
				m_insertingTowerPosition = interaction.position;
			break;

			case towerHideInserting:
				m_isInsertingTower = false;
				m_isInsertingInvalidTower = false;
			break;

			case towerInserted:
				if(!TowerManager::getInstance()->hasTower(interaction.position)) {
					if(m_money >= interaction.value && !m_isInsertingInvalidTower) {
						m_isInsertingTower = m_pInputManager->getTowerSelection();
						m_money -= TowerFactory::getBaseTowerReference(interaction.towerType)->getPrice();
						setMoney(m_money);
						TowerManager::getInstance()->createTower(interaction.position, interaction.towerType);
						
					} else if(m_isInsertingInvalidTower) {
						setWarningMsg("Torre nao pode bloquear o caminho");
						m_isInsertingTower = false;
						m_isInsertingInvalidTower = false;
						m_pInputManager->resetSelection();
					} else { //not enough money
						setWarningMsg("Dinheiro Insuficiente");
						m_isInsertingTower = false;
						m_isInsertingInvalidTower = false;
						m_pInputManager->resetSelection();
					}
				} else {
					setWarningMsg("Torre nao pode ser inserida nessa posicao");
					m_isInsertingTower = false;
					m_isInsertingInvalidTower = false;
					m_pInputManager->resetSelection();
				}
			break;

			case towerShowStaticInfo:
				m_showTowerInfo = true;
				m_showCreepInfo = false;
				m_pTowerInfo->setTargetTower(TowerFactory::getBaseTowerReference(interaction.towerType));
			break;

			case towerShowInfo:
				m_showTowerInfo = true; 
				m_showCreepInfo = false;
				m_pTowerInfo->setTargetTower(m_pInputManager->getSelectedTower());
			break;

			case towerHideStaticInfo:
				m_showTowerInfo = false;
			break;

			case towerHideInfo:
				m_showTowerInfo = false;
			break;


			case towerUpgrade:
				upgradeCost = m_pTowerInfo->getTargetTower()->getPriceToUpdate() - m_pTowerInfo->getTargetTower()->getPrice();
				if(m_money >= upgradeCost && !m_pTowerInfo->getTargetTower()->isUpgrading()) {
					m_money -= upgradeCost;
					m_pTowerInfo->getTargetTower()->upgradeLevel();
					m_pTowerInfo->updateTowerInfo();
					setMoney(m_money);
				} else if(m_money < upgradeCost) {
					setWarningMsg("Dinheiro insuficiente");
				}

			break;

			case towerSell:
				if(!TowerManager::getInstance()->getTower(interaction.value)->isUpgrading() &&
					!TowerManager::getInstance()->getTower(interaction.value)->isSelling()) {			
						m_money += m_pTowerInfo->getTargetTower()->getSellPrice();
						TowerManager::getInstance()->sellTower(interaction.value);
						m_showTowerInfo = false;
				}
			break;
			
			
			case creepShowInfo:
				m_showCreepInfo = true;
				m_pCreepInfo->setTargetCreep(m_pInputManager->getSelectedCreep());
				m_showingCreepID = m_pInputManager->getSelectedCreepID();
				m_showTowerInfo = false;
			break;

			case startNextWave:
				if(!m_gameStarted) {
					m_gameStarted = true;
					m_pWaveInfoPanel->startRolling();

					m_pBackgroundMusic->playMusic(false);
				} else if(MarioManager::getInstance()->finishedSpawning()){
					m_pWaveInfoPanel->startNextWave();
				}
			break;

			case showMenu:
				m_pMenuPanel->setVisible(true);
				m_currGameArea = gamePaused;
				TowerManager::getInstance()->updateTowers(false);
				MarioManager::getInstance()->updateMarios(false);
				m_pWaveInfoPanel->stopRolling();
				m_pPauseSound->playSound(false);
				if(m_pBackgroundMusic->isPlaying())
					m_pBackgroundMusic->pauseMusic();

			break;

			case gameExit:
				m_quit = true;
			break;
		}
	}

	void TowerDefense::processEntryScreen() {
		
		SDL_Event event;
		while(SDL_PollEvent( &event )) {
			interaction_t interaction = m_pEntryScreen->processEvent(event);

			switch(interaction.type) {
				case advanceToGame:
					m_currGameArea = playingGameArea;
					m_difficultySelected = interaction.value;
               if(!m_levelCreated) {
                  createLevel();
                  m_levelCreated = true;
               }
				break;
				case gameExit:
					m_quit = true;
				break;
			}
			if(event.type == SDL_QUIT) {
				m_quit = true;
			}
		}
		
		m_pEntryScreen->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
	}


	void TowerDefense::updateFrameRateCount() {
		
		m_numFrames++;

		if(m_fpsTimer.getTicks() < (1000/frameRate))
		{
			//Sleep the remaining frame time
			float sleepTime = (1000/frameRate) - m_fpsTimer.getTicks();
			SDL_Delay((1000/frameRate) - m_fpsTimer.getTicks());

		}

		//If a second has passed since the caption was last updated
		if( m_updateTimer.getTicks() > 1000 )
		{
			//The frame rate as a string
			stringstream caption;

			//Calculate the frames per second and create the string
			caption << "Average Frames Per Second: " << m_numFrames;
			m_numFrames = 0;
			//Reset the caption
			//SDL_WM_SetCaption( caption.str().c_str(), NULL );

			//Restart the update timer
			m_updateTimer.start();

		}
	}

	void TowerDefense::gameRestart() {
		initGameSystem();
		
		if(m_pFadescreen == NULL) {
			m_pFadescreen = new Fadescreen();
		}
		m_pFadescreen->startFadeIn(10/frameRate);
		
		setScore(0);
		setLevel(m_currWave + 1);
		setMoney(m_initialMoney);
		setLives(m_initialLives);
		m_currGameArea = playingGameArea;
		m_nextGameArea = invalidArea;
		
		m_showingCreepID = -1; //Invalid
		MarioManager::getInstance()->clear();
		TowerManager::getInstance()->clear();
		m_pWaveInfoPanel->restart();

	}
	
	void TowerDefense::renderScenario() {
		m_pMainScreen->render((1000/frameRate));
		
		//Firstly render the marios
		MarioManager::getInstance()->render(m_pMainScreen->getRootScreen(), 1000/frameRate);
		//After it, the towers
		TowerManager::getInstance()->render(m_pMainScreen->getRootScreen(), 1000/frameRate);

		
		/*m_pCloud->render(m_pMainScreen->getRootScreen(), (1000/frameRate));*/
		m_pPipeFront->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		
		

	}

	void TowerDefense::renderGUI() {
		m_pTowerMenu->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		m_pInputManager->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		m_pWaveInfoPanel->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		m_pLivesMsg->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		m_pMoneyMsg->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		m_pScoreMsg->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		m_pLevelMsg->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		if(m_isInsertingTower == true) {
			m_pInsertTowerAS->render(m_pMainScreen->getRootScreen(), (1000/frameRate), m_insertingTowerPosition);
		} else if(m_isInsertingInvalidTower) {
			m_pInsertInvalidTowerAS->render(m_pMainScreen->getRootScreen(), (1000/frameRate), m_insertingTowerPosition);
		}
		if(m_showTowerInfo) {
			m_pTowerInfo->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		} else if(m_showCreepInfo) {
			m_pCreepInfo->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		}
		
		/** Fade screen:*/
		
		if(m_pFadescreen != NULL) {
			m_pFadescreen->render(m_pMainScreen->getRootScreen(), (1000/frameRate)); 
			if(m_pFadescreen->finishedFading() && m_pFadescreen->isFadingIn()) {
				//Saving memory:
				delete m_pFadescreen;
				m_pFadescreen = NULL;
			}
		}

	}
	void TowerDefense::processGame() {

		/** Sound management. */
		if(m_gameStarted && !m_pBackgroundMusic->isPlaying()) {
			if(m_musicIndex < m_musicList.size() - 1) {
				++m_musicIndex;
			} else {
				m_musicIndex = 0;
			}
			m_pBackgroundMusic = ResourceManager::loadMusic(m_musicList[m_musicIndex]);
			m_pBackgroundMusic->playMusic(false);
		}
		
		if(m_currWave == m_waves.size() && MarioManager::getInstance()->getNumberOfMarios() == 0 && m_lives > 0) { //Last wave
			m_currGameArea = gameOverArea;
			m_pGameoverSound = ResourceManager::loadSound("SFX/sounds/win.wav");
			m_pGameoverSound->playSound(false);
			m_pBackgroundMusic->stopMusic();
			m_gameOverTimer.start();
			m_gameWin = true;
		}

		if(m_pWaveInfoPanel->getCurrentWave() != m_currWave && m_gameStarted) {
			m_currWave++;
			m_money+= 5*(((int)m_currWave/10)+1)+m_currWave%5;
			setMoney(m_money);
			setLevel(m_currWave);
			setScore(m_score + m_currWave * 20);
			if(m_waves[m_currWave - 1].marioSpeed > 9/60.0 ) { //Fast marios 
				m_pMarioHurry->playSound(false);
			}
			m_pPipeWarp->playSound(false);
			
			MarioManager::getInstance()->configSpawning(&m_terrain, 
				m_pMainScreen->getCanvasPosition() + Coord2D(-0.015625*screenWidth, 0.042968*screenHeight),  
				m_waves[m_currWave - 1]);
			
		}

		if(m_showCreepInfo) {
			if(MarioManager::getInstance()->getMarioByID(m_showingCreepID) == NULL || 
				MarioManager::getInstance()->getMarioByID(m_showingCreepID)->isDying() || 
				MarioManager::getInstance()->getMarioByID(m_showingCreepID)->isDead()) {
					m_showCreepInfo = false;		
			}
		}
		renderScenario();
		renderGUI();

		
		if(m_pFadescreen == NULL) //the fade has finished
			processGameEvents();

		if(MarioManager::getInstance()->getGoldGained() > 0) {
			//Adding money
			m_money += MarioManager::getInstance()->getGoldGained();
			setMoney(m_money);

			//Adding score
			m_score += (MarioManager::getInstance()->getGoldGained() / m_waves[m_currWave - 1].moneyPerMario ) * m_currWave;
			setScore(m_score);
			MarioManager::getInstance()->resetGoldGained();

		}

		if(MarioManager::getInstance()->getMariosPassed() > 0) {
			m_lives = m_initialLives - MarioManager::getInstance()->getMariosPassed();
			if(m_lives < 0) {
				m_lives = 0;
			}
			setLives(m_lives);
			if(m_lives == 0 && m_currGameArea != gameOverArea) {
				m_currGameArea = gameOverArea;
				m_pGameoverSound = ResourceManager::loadSound("SFX/sounds/dyingmario.wav");
				m_pGameoverSound->playSound(false);
				m_pBackgroundMusic->stopMusic();
				m_gameOverTimer.start();
				m_gameWin = false;
			}
			if(m_oldLives != m_lives) {
				m_oldLives = m_lives;
				float randMarioSFX = Utils::randomNumber(1000)/1000.0;
				if(randMarioSFX < 0.4) {
					m_pMarioPassed1->playSound(false);
				} else if(randMarioSFX < 0.9) {
					m_pMarioPassed2->playSound(false);
				} else {
					m_pMarioPassed3->playSound(false);
				}
			}
		}

	
		if(m_pWarningMsg != NULL) {
			m_pWarningMsg->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
		}
		
	}

	void TowerDefense::processPauseEvents() {
		interaction_t interaction;
		interaction = m_pInputManager->process(m_pMainScreen, (1000/frameRate));

		switch (interaction.type) {
			case creepShowInfo:
				m_showCreepInfo = true;
				m_pCreepInfo->setTargetCreep(m_pInputManager->getSelectedCreep());
				m_showingCreepID = m_pInputManager->getSelectedCreepID();
				m_showTowerInfo = false;
				break;

			
			case hideMenu:
				m_pMenuPanel->setVisible(false);
				m_currGameArea = playingGameArea;
				TowerManager::getInstance()->updateTowers(true);
				MarioManager::getInstance()->updateMarios(true);

				if(m_gameStarted) {
					m_pWaveInfoPanel->startRolling();
					m_pBackgroundMusic->resumeMusic();
				}
				break; 
			case restartGame:
				gameRestart();
			break;
			case gameExit:
				m_quit = true;
			break;
		}

	}
	
	void TowerDefense::processGamePaused() {
		processPauseEvents();
		
		/**Renders the scenario and gui*/
		renderScenario();
		renderGUI();
		m_pMenuPanel->render(m_pMainScreen->getRootScreen(), (1000/frameRate));

		

	}

	void TowerDefense::processGameOver() {
		if(m_pGameOverScreen == NULL) {
			m_pGameOverScreen = new GameOverScreen(m_gameWin);
			
		}
		SDL_Event event;
		while(SDL_PollEvent( &event )) {
			interaction_t interaction = m_pGameOverScreen->processEvent(event);
			
			switch(interaction.type) {
				case restartGame:
					gameRestart();
				break;

				case gameExit:
					m_quit = true;
					break;
			}
			if(event.type == SDL_QUIT) {
				m_quit = true;
			}
		}
		m_pGameOverScreen->render(m_pMainScreen->getRootScreen(), (1000/frameRate));

		
	}
	/** Main game loop:*/
	void TowerDefense::process() {
		//Restart the FPS counter
		m_fpsTimer.start();
		
		if(m_nextGameArea != invalidArea) {
			if(m_pFadescreen->isFadingOut() && m_pFadescreen->finishedFading()) {
				m_currGameArea = m_nextGameArea;
				if(m_pFadescreen == NULL) 
					m_pFadescreen = new Fadescreen();
				m_pFadescreen->startFadeIn(10/frameRate);
			}
		}
		switch(m_currGameArea) {
			case atEntryScreen:
				processEntryScreen();
			break;
			case playingGameArea:
				/**Fixing interaction w fadeout glitch*/

				if(m_pEntryScreen != NULL && !m_pEntryScreen->isFinished()) {
					processEntryScreen();
				} else {
					if(m_pEntryScreen != NULL && m_pEntryScreen->isFinished()) {
						if(m_pFadescreen == NULL) 
							m_pFadescreen = new Fadescreen();
						m_pFadescreen->startFadeIn(10/frameRate);

						delete m_pEntryScreen;
						m_pEntryScreen = NULL;
					}
					processGame();
				}
			break;

			case gameOverArea:
				if(m_gameOverTimer.getTicks() > 4000) {
					processGameOver();	
				} else {
					renderScenario();
					renderGUI();
					m_pMenuPanel->render(m_pMainScreen->getRootScreen(), (1000/frameRate));
				}			
			break;
			case gamePaused:
				processGamePaused();
			break;
		}
		

		
		//Equivalent to openGL swap buffers 
		if(SDL_Flip(m_pMainScreen->getRootScreen()) == -1) {
			return ;
		}

		updateFrameRateCount();
		
	}

	
}